using PioneerBoilerplate.Service.Admin.Auth.Input;
using PioneerBoilerplate.Service.Admin.Auth.Output;
using System;
using System.Linq;
using System.Threading.Tasks;
using PioneerBoilerplate.Service.Base;
using PioneerBoilerplate.Util.Configs;
using PioneerBoilerplate.Repository;
using PioneerBoilerplate.Util.Helpers;
using PioneerBoilerplate.Util.Output;
using PioneerBoilerplate.Util.Cache;
using PioneerBoilerplate.Model.Admin;
using PioneerBoilerplate.Util;
using Microsoft.EntityFrameworkCore;
using PioneerBoilerplate.Tools.Captcha;
using PioneerBoilerplate.Enums;

namespace PioneerBoilerplate.Service.Admin.Auth
{
    public class AuthService : BaseService, IAuthService
    {
        private readonly AppConfig _appConfig;
        private readonly VerifyCodeHelper _verifyCodeHelper;
        private readonly IUserRepository _userRepository;
        private readonly IBaseRepository<ApplicationDbContext, RolePermissionEntity> _rolePermissionBaseRepository;
        private readonly IBaseRepository<ApplicationDbContext, UserRoleEntity> _userRoleBaseRepository;
        private readonly ICaptcha _captcha;

        public AuthService(
            AppConfig appConfig,
            VerifyCodeHelper verifyCodeHelper,
            IUserRepository userRepository,
            IBaseRepository<ApplicationDbContext, RolePermissionEntity> rolePermissionBaseRepository,
            IBaseRepository<ApplicationDbContext, UserRoleEntity> userRoleBaseRepository,
            ICaptcha captcha
        )
        {
            _appConfig = appConfig;
            _verifyCodeHelper = verifyCodeHelper;
            _userRepository = userRepository;
            _rolePermissionBaseRepository = rolePermissionBaseRepository;
            _userRoleBaseRepository = userRoleBaseRepository;
            _captcha = captcha;
        }

        public async Task<IResponseOutput> GetPassWordEncryptKeyAsync()
        {
            //写入Redis
            var guid = Guid.NewGuid().ToString("N");
            var key = string.Format(CacheKey.PassWordEncryptKey, guid);
            var encyptKey = StringHelper.GenerateRandom(8);
            await Cache.SetAsync(key, encyptKey, TimeSpan.FromMinutes(5));
            var data = new { key = guid, encyptKey };

            return ResponseOutput.Ok(data);
        }

        public async Task<IResponseOutput> GetUserInfoAsync()
        {
            if (!(User?.Id > 0))
            {
                return ResponseOutput.NotOk("未登录！");
            }

            var authUserInfoOutput = new AuthUserInfoOutput { };
            //用户信息
            authUserInfoOutput.User = (await _userRepository.GetAllListAsync(a => a.Id == User.Id))
                .Select(a => new AuthUserProfileDto
                {
                    Avatar = a.Avatar,
                    UserName = a.UserName,
                    NickName = a.NickName
                }).FirstOrDefault();

            //用户角色
            var roles = (await _userRoleBaseRepository.GetAllListAsync(a => a.UserId == User.Id)).Select(a => a.RoleId).ToList();

            //用户菜单
            authUserInfoOutput.Menus = await _rolePermissionBaseRepository.GetAll()
                .Include(p => p.Permission)
                .ThenInclude(v => v.View)
                .Where(a => roles.Contains(a.RoleId) &&
                  new[] { PermissionType.Group, PermissionType.Menu }.Contains(a.Permission.Type))
                .OrderBy(o => o.Permission.ParentId)
                .ThenBy(o => o.Permission.Sort)
                .Select(a => new AuthUserMenuDto 
                {
                    Id = a.PermissionId,
                    Closable = a.Permission.Closable,
                    External = a.Permission.External,
                    Hidden = a.Permission.Hidden,
                    Icon = a.Permission.Icon,
                    Label = a.Permission.Label,
                    NewWindow = a.Permission.NewWindow,
                    Opened = a.Permission.Opened,
                    ParentId = a.Permission.ParentId,
                    ViewPath = a.Permission.View.Path,
                    Path=a.Permission.Path
                }).ToListAsync();

            //用户权限点
            authUserInfoOutput.Permissions = await _rolePermissionBaseRepository.GetAll()
                .Include(p => p.Permission)
                .Where(a => roles.Contains(a.RoleId)&& a.Permission.Type == PermissionType.Dot)
                .Select(s => s.Permission.Code)
                .ToListAsync();

            return ResponseOutput.Ok(authUserInfoOutput);
        }

        public async Task<IResponseOutput> GetVerifyCodeAsync(string lastKey)
        {
            var img = _verifyCodeHelper.GetBase64String(out string code);

            //删除上次缓存的验证码
            if (lastKey.NotNull())
            {
                await Cache.DelAsync(lastKey);
            }

            //写入Redis
            var guid = Guid.NewGuid().ToString("N");
            var key = string.Format(CacheKey.VerifyCodeKey, guid);
            await Cache.SetAsync(key, code, TimeSpan.FromMinutes(5));

            var data = new AuthGetVerifyCodeOutput { Key = guid, Img = img };
            return ResponseOutput.Ok(data);
        }

        public async Task<IResponseOutput> LoginAsync(AuthLoginInput input)
        {
            #region 验证码校验

            if (_appConfig.VarifyCode.Enable)
            {
                //    var verifyCodeKey = string.Format(CacheKey.VerifyCodeKey, input.VerifyCodeKey);
                //    var exists = await Cache.ExistsAsync(verifyCodeKey);
                //    if (exists)
                //    {
                //        var verifyCode = await Cache.GetAsync(verifyCodeKey);
                //        if (string.IsNullOrEmpty(verifyCode))
                //        {
                //            return ResponseOutput.NotOk("验证码已过期！", 1);
                //        }
                //        if (verifyCode.ToLower() != input.VerifyCode.ToLower())
                //        {
                //            return ResponseOutput.NotOk("验证码输入有误！", 2);
                //        }
                //        await Cache.DelAsync(verifyCodeKey);
                //    }
                //    else
                //    {
                //        return ResponseOutput.NotOk("验证码已过期！", 1);
                //    }
                //input.Captcha.DeleteCache = true;
                //var isOk = await _captcha.CheckAsync(input.Captcha);
                //if (!isOk)
                //{
                //    return ResponseOutput.NotOk("安全验证不通过，请重新登录！");
                //}
            }

            #endregion 验证码校验

            UserEntity user = null;

            user = await _userRepository.FirstOrDefaultAsync(a => a.UserName == input.UserName);

            if (!(user?.Id > 0))
            {
                return ResponseOutput.NotOk("账号输入有误!", 3);
            }

            #region 解密

            if (input.PasswordKey.NotNull())
            {
                var passwordEncryptKey = string.Format(CacheKey.PassWordEncryptKey, input.PasswordKey);
                var existsPasswordKey = await Cache.ExistsAsync(passwordEncryptKey);
                if (existsPasswordKey)
                {
                    var secretKey = await Cache.GetAsync(passwordEncryptKey);
                    if (secretKey.IsNull())
                    {
                        return ResponseOutput.NotOk("解密失败！", 1);
                    }
                    input.Password = DesEncrypt.Decrypt(input.Password, secretKey);
                    await Cache.DelAsync(passwordEncryptKey);
                }
                else
                {
                    return ResponseOutput.NotOk("解密失败！", 1);
                }
            }

            #endregion 解密

            var password = MD5Encrypt.Encrypt32(input.Password);
            if (user.Password != password)
            {
                return ResponseOutput.NotOk("密码输入有误！", 4);
            }

            var authLoginOutput = Mapper.Map<AuthLoginOutput>(user);
            return ResponseOutput.Ok(authLoginOutput);
        }
    }
}